# Copyright 2007 Boris Dusek
#
# This file is part of grapy.
#
# Grapy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# Grapy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Grapy.  If not, see <http://www.gnu.org/licenses/>.

class Matrix:

    def __init__(self):
        self.data = []
    
    def extend(self, rows_new, cols_new, pad=0):
        for row in self.rows():
            row.extend ((cols_new - len(row)) * [pad])
        self.data.extend ([cols_new * [pad] for i in
            xrange (rows_new - len(self.data))])

    def __getitem__(self, key):
        return self.data.__getitem__(key)

#    def __setitem__(self, key, value):
#        return self.data.__setitem__(key, value)

    def rows(self):
        for row in self.data:
            yield row

    def columns(self):
        for column_index in xrange(self.columns_count()):
            yield [self.data[i][column_index] for i in xrange(self.rows_count())]

    def rows_count(self):
        return len(self.data)

    def columns_count(self):
        if self.rows_count():
            return len(self.data[0])
        else:
            return 0

    def dimension(self):
        return (rows_count(), columns_count())


    def row(self, key):
        i = 0
        for i in xrange(self.columns_count()):
            yield self.data[key][i]

    def column(self, key):
        i = 0
        for i in xrange(self.rows_count()):
            yield self.data[i][key]

    def transpose(self):
        for i in xrange(self.columns_count()):
            for j in xrange(i):
                self.data[i][j], self.data[j][i] = self.data[j][i], self.data[i][j]

    @staticmethod
    def mul (m1, m2):
        assert m1.columns_count() == m2.rows_count()
        ret = Matrix()
        ret.extend (m1.rows_count(), m2.columns_count())
        for i, row in enumerate (m1.rows()):
            for j, column in enumerate (m2.columns()):
                ret[i][j] = 0
                for k in xrange(len(row)):
                    ret[i][j] += row[k] * column[k]
        return ret

    @staticmethod
    def from_stream(stream):
        ret = Matrix()
        for line in stream:
            ret.data.append([int(i) for i in line.split()])
        _len = len(ret[0])
        for row in ret.rows():
            assert len(row) == _len
        return ret

    def __str__(self):
        ret = ""
        first_row = True
        for row in self.rows():
            if first_row:
                first_row = False
            else:
                ret += "\n"
            for item in row:
                ret += "%4d " % item
        return ret
